--[[
-- Author: SUYINXIANG
-- Date: 2018-07-28 16:31:59
示例
local timer = require("timer").new()
local curtime = os.time()
for i=1,10 do
    local ID = timer:schedule(function ( param )
        -- skynet.sleep(2*100)
        print("time out=",param,curtime+i,os.time())
    end,curtime+i,"test" .. i)
    timer:delay(ID,1)
end
timer:start()
--]]

require("sharefunc")

local skynet = require("skynet")

local zset = require("zset")

-- 定时器
local timer = class("timer")

local defaultRefreshTime = 1

------------------API--------------------
function timer.create( fun, time )
    local sche = timer.new()
    sche:scheduleUpdate(fun)
    sche:setRefreshTime(time)
    return sche
end

-- 获取定时器数量
function timer.gettimerCount()
    return self.zset:count()
end

-- 设置刷新函数
function timer:schedule(fun,endtime,param,repeats)
    if "function" == type(fun) then
        assert(self.list[self.ID] == nil,"timer ID is duplicate")
        local retID = self.ID
        local ID = tostring(self.ID)
        -- item[1] = 回调函数,item[2] = 参数,item[3] = 是否重复,item[4] = 定时间隔
        local interval = endtime - os.time()
        if repeats then assert(interval>0,"if repeats then interval must > 0") end
        self.list[ID] = {fun,param,repeats,interval}
        self.zset:add(endtime,ID)
        self.ID = self.ID + 1
        return retID
    end
    return nil
end

-- 设置定时器刷新时间
function timer:setRefreshTime(time)
    if "number" == type(time) and time > 0 then
        self.refreshTime_ = time
    end
end

-- 获取定时器刷新时间
function timer:getRefreshTime()
    return self.refreshTime_
end

-- 启动计时器
function timer:start()
    self.continue = true
    if self.timerCo then
        skynet.wakeup(self.timerCo)
    end
end

-- 暂停计时器
function timer:pause()
    self.continue = false
end

-- 刷新
function timer:update(dt)
    local ret = self.zset:range_by_score(0,os.time())
    for _, ID in ipairs(ret) do
        local item = self.list[ID]
        if item then
            if not item[3] then
                self.list[ID] = nil
                self.zset:rem(ID)
            elseif item[4] then --重复性计时器
                if item[4] ~= 1 then -- 每秒的无需每次都添加
                    self.zset:add(os.time() + item[4],ID)
                end
            end
            -- print("ID=",ID,os.time())
            skynet.fork(item[1],item[2],dt)
        end
    end
end

-- 更新计时器ID到某一时刻
function timer:reset( timerID, newEndtime )
    if timerID and newEndtime and type(newEndtime) == "number" then
        local ID = tostring(timerID)
        local score = self.zset:score(ID)
        if score then
            self.zset:add(newEndtime,ID)
            return true
        end
    end
    return false
end

-- 加速计时器ID,提前n秒结束
function timer:speedup( timerID, second )
    if timerID and second and type(second) == "number" and second > 0 then
        local ID = tostring(timerID)
        local endtime = self.zset:score(ID)
        if endtime then
            self.zset:add(endtime-second,ID)
            return true
        end
    end
    return false
end

-- 加速计时器ID,延迟n秒结束
function timer:delay( timerID, second )
    if timerID and second and type(second) == "number" and second > 0 then
        local ID = tostring(timerID)
        local endtime = self.zset:score(ID)
        if endtime then
            self.zset:add(endtime+second,ID)
            return true
        end
    end
    return false
end

-- 停止计时器ID
function timer:stop( timerID )
    if timerID then
        local ID = tostring(timerID)
        local item = self.list[ID]
        if item then
            self.list[ID] = nil
            self.zset:rem(ID)
        end
    end
    return false
end

-- 清空所有计时器
function timer:clear( )
    self.zset:limit(0)
    self.list = nil
    self.list = {}
end

-- 是否正在运行
function timer:isRunning()
    return self.continue
end

----------------------------------------

local function coFun(self)
    while true do
        if self.continue then
            if not self.lastUpdateTime then
                self.lastUpdateTime = skynet.time()
            end
            skynet.sleep(self:getRefreshTime() * 100)
            self:update(skynet.time() - self.lastUpdateTime)
            self.lastUpdateTime = skynet.time()
        else
            skynet.wait()
        end
    end
end

function timer:ctor()
    self:setRefreshTime(defaultRefreshTime)
    -- 是否继续运行，默认未不继续
    self.continue = false
    self.list = {}
    self.ID = 1
    self.zset = zset.new()
    -- 定时器协程
    self.timerCo = skynet.fork(coFun, self)
end

return timer